// ============================================================================
// JigServerThread
// The JigServerThread provides the communication with a player. There is
// one thread per player.
//
// CLH April-June 1998
// ============================================================================

package com.chrishobson.jiggle;

import java.net.*;

public class JigServerThread extends Thread {

  // ==========================================================================
  // Constructs a new thread which talks to the socket and the server
  // ==========================================================================
  JigServerThread(Socket sock, JigServer server) {
    m_parser = new JigParser();
    m_sock = new JigSocket(sock);
    m_server = server;
  }

  // ==========================================================================
  // Each thread has a unique id which is set by this method
  // ==========================================================================
  public void set_id(int id) {
    m_id = id;
  }

  // ==========================================================================
  // Returns the players command LEFT RIGHT etc.
  // ==========================================================================
  public int get_command() {
    return m_command;
  }

  // ==========================================================================
  // Used set the current command, certain command take priority can canot
  // be overwritten
  // ==========================================================================
  public void set_command(int com) {
    if (m_command == JigServer.NONE) {
      m_command = com;
    } else if (com == JigServer.DIE || com == JigServer.DEAD) {
      if (m_command != JigServer.DEAD) {
        m_command = com;
      }
    } else if (com == JigServer.NONE && m_command != JigServer.DEAD) {
      m_command = com;
      // Killed is a temp command use by the server to flag
      // that the worm is dead but that the thread is still
      // listening. It allows the client to undraw the killed
      // worm and carry on viewing the action
    } else if (m_command == JigServer.KILLED) {
      m_command = com;
    }
  }

  // ==========================================================================
  // The threads run loop, the thread just loops for command from the
  // client with a regular yield to give up its timeslice
  // ==========================================================================
  public void run() {
    // We exit when our command goes to the DEAD which indicates that
    // the JigServer has handled our death and we are free to go
    while (m_command != JigServer.DEAD) {
      if (m_command != JigServer.DIE) {
        String l = m_sock.get();
        if (m_sock.ok() == false) {
          // Out client has vanished, flag that we wish to die
          m_command = JigServer.DIE;
          System.out.println("Client " + m_id + " Lost connection");
        } else if (l != null) {
          handle(l);
        }
      }
      yield();
    }
    // Close the socket on the way out, we are not talking any more.
    m_sock.close();
  }

  // ==========================================================================
  // Is this thread currently a game listener.
  // Returns true if the client has been sent the full state
  // of the game and so it is now an active game listener
  // ==========================================================================
  public boolean is_listener() {
    return m_listener;
  }

  // ==========================================================================
  // Is this thread currently a game player.
  // Returns true if the client has been allowed to join the game
  // and so it is allowed to issue move requests to the game server.
  // ==========================================================================
  public boolean is_player() {
    return m_player;
  }

  // ==========================================================================
  // Tells this thread that the client has joined the game and is now playing
  // ==========================================================================
  public void join_game(String wormstr) {
    m_worm = new JigWorm(wormstr);
    m_player = true;
  }

  // ==========================================================================
  // Tells this thread that the client has left the game and
  // is now just listening
  // ==========================================================================
  public void leave_game() {
    m_worm = null;
    m_player = false;
  }

  // ==========================================================================
  // Returns the worm associated with this player
  // ==========================================================================
  public final JigWorm get_worm() {
    return m_worm;
  }

  // ==========================================================================
  // Sends the string to the client via the socket connection
  // ==========================================================================
  public void send(String command) {
    m_sock.send(command);
  }

  // ==========================================================================
  // Handles a command line read from the client
  // ==========================================================================
  private void handle(String l) {
    System.out.println("From Client " + m_id + " " + l);
    // A debug message for the demonstration

    m_parser.reset(l);
    char c = m_parser.next_char();

    // The first character defines the major command which can be used
    // to switch on
    switch (c) {
    case 'D': {
      System.out.println("It's a dimension command");
      // The dimension command can be handled straight away by
      // getting the server to send its sizes
      m_server.send_sizes(m_sock);
      break;
    }
    case 'I': {
      System.out.println("It's an ID command");
      m_sock.send("I" + m_id);
      break;
    }
    case 'Q': {
      System.out.println("It's a QUIT command");
      set_command(JigServer.QUIT);
      break;
    }
    case 'J': {
      System.out.println("It's a Request to join");
      // If we are not already a player then set out join
      // flag so that the gaming server knows that we want to
      // join the game.
      set_command(JigServer.JOIN);
      break;
    }
    case 'R': {
      System.out.println("It's a Right Move");
      if (m_player == true) {
        set_command(JigServer.RIGHT);
      }
      break;
    }
    case 'L': {
      System.out.println("It's a Left Move");
      if (m_player == true) {
        set_command(JigServer.LEFT);
      }
      break;
    }
    case 'S': {
      System.out.println("It's a game status request");
      // Request that the server dump the whole game
      // down the socket. There server must do this so that
      // game changes are locked out during the sending
      m_server.send_game(m_sock);
      m_listener = true;
      break;
    }
    }
  }

  // ==========================================================================
  // Private member data
  // ==========================================================================
  private JigParser m_parser;
  private JigSocket m_sock;
  private JigServer m_server;
  private int m_id;
  private boolean m_listener;
  private boolean m_player;
  private JigWorm m_worm;
  private int m_command;
}
